package com.bvbot.core.order;

import static com.bvbot.core.Logger.log;

import java.math.BigDecimal;

import com.bvbot.core.session.BalanceResponse;
import com.bvbot.core.session.BuyResponse;
import com.bvbot.core.session.BvSession;
import com.bvbot.core.session.BvSessionException;
import com.bvbot.core.session.MarketResponse;

public class SecurityBuyer extends AbstractOrderGiver {

	private boolean gold;

	public SecurityBuyer(boolean isGold) {
		setGold(isGold);
	}

	private String getSecurity() {
		return isGold() ? "gold" : "silver";
	}

	public void buyRatio(float ratio) {
		log("Buy " + ratio + "/1 of " + getSecurity() + " - START");
		int numberOfGramsToBuy = 0;
		try {
			BvSession session = new BvSession();
			session.start();
			numberOfGramsToBuy = computeGramsToBuy(session, ratio);
			buyGrams(numberOfGramsToBuy);
		} catch (Exception e) {
			log("Exception occured in " + getSecurity() + " sale : "
					+ e.getMessage(), e);
		}
		log("Buy " + ratio + "/1 of " + getSecurity() + " - STOP");
	}

	public void buyGrams(int gramsNumber) {
		log("buyGrams : " + gramsNumber + " to buy . START");
		Buy buy = new Buy(gramsNumber, 0);
		if (gramsNumber > 0) {
			try {
				BvSession session = new BvSession();
				session.start();
				doBestBuy(buy, session);
			} catch (Exception e) {
				log("Exception occured in " + getSecurity() + " buy : "
						+ e.getMessage(), e);
			}
		}
		log("buyGrams : " + gramsNumber + " to buy. END");
	}

	private void doBestBuy(Buy buy, BvSession session)
			throws BvSessionException {
		boolean workToDo = true;
		while (workToDo) {
			BuyResponse resp = doBuy(buy, session);
			if (buy.allIsBought() || (resp.isErrorResponse())) {
				if (resp.isErrorResponse()) {
					log("Error in the response. Buy cancelled");
				}
				workToDo = false;
			}
		}
		log("Buy of " + buy.getGramsToBuy() + " grams finished : "
				+ buy.getGramsBought() + " grams bought.");
	}

	private BuyResponse doBuy(Buy buy, BvSession session)
			throws BvSessionException {
		MarketResponse mr = null;
		if (isGold()) {
			mr = session.getGoldMarket();
		} else {
			mr = session.getSilverMarket();
		}
		BigDecimal marketAskPrice = mr.computeLowestSellPrice();
		BuyResponse sr = session.buy(marketAskPrice,
				buy.getNextOfferGramNumber(), isGold());
		int gramsBought = sr.getGramsBought();
		buy.declareBoughtGrams(gramsBought);
		log(sr.getSummary());
		return sr;
	}

	protected int computeGramsToBuy(BvSession session, float ratio)
			throws BvSessionException {
		int result = -1;
		BalanceResponse response = session.getBalance();
		BigDecimal dolls = response.getDollarsAsBd();
		BigDecimal dollsToSell = dolls.multiply(new BigDecimal(ratio));
		BigDecimal sellLimit = dolls.subtract(new BigDecimal("60"));
		if (sellLimit.compareTo(new BigDecimal("0")) < 0) {
			sellLimit = new BigDecimal("0");
		}
		if (dollsToSell.compareTo(sellLimit) > 0) {
			dollsToSell = sellLimit;
		}
		MarketResponse mr = null;
		if (isGold()) {
			mr = session.getGoldMarket();
		} else {
			mr = session.getSilverMarket();
		}
		BigDecimal price = mr.computeLowestSellPrice();
		// price in grams
		price = price.divide(new BigDecimal("1000"));
		BigDecimal gramsBd = dollsToSell.divideToIntegralValue(price);
		result = gramsBd.intValue();
		log("" + result + " grams will be bought. Available dollars is "
				+ dolls + " and lowest sell price is " + price);
		return result;
	}

	public static void main(String[] args) {
		SecurityBuyer buyer = new SecurityBuyer(false);
		buyer.buyGrams(1);
	}

	private void setGold(boolean gold) {
		this.gold = gold;
	}

	public boolean isGold() {
		return gold;
	}
}
